#include "triangulation.h"
#include "datastructures.h"
#include "poly2tri/poly2tri.h"
#include "cmath.h"
#include <stdlib.h>
//=========================================================================
void triangulateContoursP2T(std::vector <Contour *> &contours, std::vector <Point*> *points, std::vector <Triangle*> *triangles)
{
     std::vector<p2t::Point*> polyline;
     std::vector< std::vector <p2t::Point*> > halls;

     for (int i =0; i< contours[0]->points.size(); i++)
         polyline.push_back(new p2t::Point(contours[0]->points[i]->x,contours[0]->points[i]->y));

     for (int i = 1; i< contours.size(); i++)
     {
         halls.push_back(std::vector <p2t::Point *> ());
         for (int j =contours[i]->points.size()-1; j>=0; j--)
             halls[i-1].push_back(new p2t::Point(contours[i]->points[j]->x,contours[i]->points[j]->y));
     }
     p2t::CDT* cdt = new p2t::CDT(polyline);

     for (int i = 0; i< halls.size(); i++)
         cdt->AddHole(halls[i]);

   cdt->Triangulate();
   std::vector<p2t::Triangle*> trg;

   trg = cdt->GetTriangles();

   for (int i =0; i<trg.size(); i++)
   {

       p2t::Triangle& t = *trg[i];

       p2t::Point& a = *t.GetPoint(0);
       p2t::Point& b = *t.GetPoint(1);
       p2t::Point& c = *t.GetPoint(2);


       Point *p1 = new Point(a.x,a.y,0,0);
       Point *p2 = new Point(b.x,b.y,0,0);
       Point *p3 = new Point(c.x,c.y,0,0);

       points->push_back(p1);
       points->push_back(p2);
       points->push_back(p3);

       triangles->push_back(new Triangle(p1,
                             p2,
                             p3,0,0));
    }

}

//=========================================================================
void triangulateContoursMy(std::vector <Contour *> &contours, std::vector <Point*> *points, std::vector <Triangle*> *triangles)
{
  int i, t;
  int counter=0;
  bool newTriangle;
  //первые 3 вершины

  SList <Point*> lp;
  //make single countour:
  //1. find points to make cut for each hole with main contour
  std::vector <double> min_distanses;
  std::vector <int> min_point_c1;
  std::vector <int> min_point_c2;

  /* if(contours.size() > 1)
  {
        min_distanses.reserve(contours.size()-1);
        min_point_c1.reserve(contours.size()-1);
        min_point_c2.reserve(contours.size()-1);

       for (int k =1; k<contours.size(); k++)
        {
            min_distanses.push_back( distance(*(contours[0]->points[0]),*(contours[k]->points[0])));
            min_point_c1.push_back(0);
            min_point_c2.push_back( 0);
            for (int i =0; i<contours[0]->points.size(); i++)
            {
                for (int j =0; j<contours[k]->points.size(); j++)
                {
                    if (min_distanses[k-1] > distance(*(contours[0]->points[i]),*(contours[k]->points[j])))
                    {
                        min_distanses[k-1] =  distance(*(contours[0]->points[i]),*(contours[k]->points[j]));
                        min_point_c1[k-1] = i;
                        min_point_c2[k-1] = j;
                    }
                }
             }
        }
  }

  for (int i =0; i<contours[0]->points.size(); i++)
  {
      lp.appendtoTail(contours[0]->points[i]);
      printf("app point %d from 0\n",contours[0]->points[i]->index);
      for (int k =1; k<contours.size(); k++)
      {
          if (i == min_point_c1[k-1])
          {
                for (int l =min_point_c2[k-1]; l< contours[k]->points.size(); l++)
                {
                    lp.appendtoTail(contours[k]->points[l]);
                    printf("app point %d from %d\n",contours[k]->points[l]->index,k);
                }

                for (int l = 0; l<=min_point_c2[k-1]; l++)
                {
                    printf("app point %d from %d\n",contours[k]->points[l]->index,k);
                    lp.appendtoTail(contours[k]->points[l]);
                }

                printf("app point %d from 0\n",contours[0]->points[i]->index);
                lp.appendtoTail(contours[0]->points[i]);
          }
      }
  }
*/
  Node<Point*> *pn1 = lp.head;
  for (int i = 0; i<rand()% points->size(); i++)
      pn1 = pn1->next;

  Node<Point*> *pn2 = pn1->next;
  Node<Point*> *pn3 = pn2->next;
  Node<Point*> *it1;

  //определяем направление обхода многоугольника
  double direction;

  direction = -1;
  //пока не останется 3 точки
  while( lp.size != 3 )
  {
      counter++;
      if (counter > points->size()*points->size())
          return;
      //если вектора образуют правую тройку
      if( vec_mult( *pn2->p, *pn1->p, *pn3->p ) * direction > 0 )
      {
          newTriangle = true;

          //проверка не попала ли вершина в отсекаемый треугольник
          for( it1 = pn3->next; it1 != pn1; it1 = it1->next )
              if( isInTriangle(*it1->p, *pn1->p, *pn2->p, *pn3->p) )
              {
                  newTriangle = false; //вершина попала в отсекаемый треугольник
                  pn1 = pn1->next; //переходим к следующей вершине
                  break;
              }
          if( newTriangle == true )//вершина не попала в отсекаемый треугольник
          {
              //заносим в vector новый треугольник
              triangles->push_back(new Triangle(pn1->p,
                                            pn2->p,
                                            pn3->p,
                                            0,0));
              //удаляем вершину из списка
              lp.delete_(pn2->key);
          }
          //сдвигаем 2ю и 3ю вершины

          //pn1 = pn1->next;
          pn2 = pn3;
          pn3 = pn3->next;
      }
      else //вектора не образуют правую тройку,  сдвигаем 3 вершины
      {
          pn1 = pn2;
          pn2 = pn3;
          pn3 = pn3->next;

      }
  }
  //заносим в vector оставшийся треугольник

  triangles->push_back(new Triangle(lp.head->p,
                                    lp.head->next->p,
                                    lp.head->next->next->p,
                                    triangles->size(),triangles->size()));


}

//=========================================================================
void sharpTriangulationByArea(std::vector <Point*> *points, std::vector <Triangle*> *triangles, double min_s)
{
    double maximum_area = triangles->at(0)->area();
    bool run = true;
    while (run)
    {
        run = false;
        for (int i =0; i < triangles->size(); i++)
        {
            Triangle *current = triangles->at(i);

            if (current->area() > min_s)
            {
                run = true;
                //do points devision
                Point tr_center = current->center();
                Point *new_point = new Point(tr_center);
                points->push_back(new_point);
                triangles->push_back(new Triangle(current->p1,current->p2,new_point,0,current->param));
                triangles->push_back(new Triangle(current->p2,current->p3,new_point,0,current->param));
                triangles->push_back(new Triangle(current->p1,current->p3,new_point,0,current->param));

                triangles->erase(triangles->begin()+i);
                delete current;
                break;
            }
        }
    }
}

//=========================================================================
void sharpOnce(std::vector <Point*> *points, std::vector <Triangle*> *triangles)
{
    std::vector < Triangle *> new_triangles;
    for (int i =0; i < triangles->size(); i++)
    {
        Triangle *current = triangles->at(i);


        //do points devision
        Point tr_center = current->center();
        Point *new_point = new Point(tr_center);
        points->push_back(new_point);
        new_triangles.push_back(new Triangle(current->p1,current->p2,new_point,0,current->param));
        new_triangles.push_back(new Triangle(current->p2,current->p3,new_point,0,current->param));
        new_triangles.push_back(new Triangle(current->p1,current->p3,new_point,0,current->param));
        delete current;
    }
    triangles->clear();
    triangles->assign(new_triangles.begin(),new_triangles.end());

}
